"""
区域分析服务
基于地理位置进行信访数据的区域分析和可视化
"""
from typing import Dict, Any, List, Optional
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy import func, desc, and_, or_
import json

from .base_analyzer import BaseAnalyzer, AnalysisFilters, AnalysisResult
from models.petition_record import RegionalAnalysisResult
from models.analysis_task import AnalysisTask
from core.logging_config import get_logger

# 日志记录器
logger = get_logger("regional_analyzer")


class RegionalAnalysisFilters(AnalysisFilters):
    """区域分析过滤器"""

    def __init__(self):
        super().__init__()
        self.has_coordinates: Optional[bool] = None  # 是否有经纬度
        self.region_level: Optional[str] = None  # 区域级别: city, district, street
        self.min_confidence: Optional[float] = None  # 最小置信度


class RegionalAnalyzer(BaseAnalyzer):
    """区域分析器"""

    def get_model_class(self):
        """获取数据模型类"""
        return RegionalAnalysisResult

    def analyze_data(self, filters: RegionalAnalysisFilters) -> AnalysisResult:
        """分析区域数据"""
        try:
            # 构建查询
            query = self.build_base_query(filters)

            # 应用特殊筛选
            if filters.has_coordinates is not None:
                if filters.has_coordinates:
                    query = query.filter(
                        and_(
                            RegionalAnalysisResult.dzxx_lng.isnot(None),
                            RegionalAnalysisResult.dzxx_lat.isnot(None),
                            RegionalAnalysisResult.dzxx_lng != '',
                            RegionalAnalysisResult.dzxx_lat != ''
                        )
                    )
                else:
                    query = query.filter(
                        or_(
                            RegionalAnalysisResult.dzxx_lng.is_(None),
                            RegionalAnalysisResult.dzxx_lat.is_(None),
                            RegionalAnalysisResult.dzxx_lng == '',
                            RegionalAnalysisResult.dzxx_lat == ''
                        )
                    )

            # 获取基础统计
            basic_stats = self.get_basic_statistics(filters)

            # 获取区域分布
            regional_distribution = self.get_regional_distribution(query, filters)

            # 获取地理分布
            geographical_data = self.get_geographical_data(query, filters)

            # 获取置信度分布
            confidence_distribution = self.get_confidence_distribution(query, filters)

            # 获取时间趋势
            time_series = self.get_time_series_data(filters, 'day')

            # 组装结果
            result_data = {
                "basic_statistics": basic_stats,
                "regional_distribution": regional_distribution,
                "geographical_data": geographical_data,
                "confidence_distribution": confidence_distribution,
                "time_series": time_series,
                "analysis_metadata": {
                    "total_records": query.count(),
                    "filtered_records": len(geographical_data),
                    "coordinate_coverage": self._calculate_coordinate_coverage(query),
                    "analysis_time": datetime.now().isoformat()
                }
            }

            return AnalysisResult(
                success=True,
                data=result_data,
                message="区域分析完成"
            )

        except Exception as e:
            logger.error(f"区域分析失败: {str(e)}")
            return AnalysisResult(
                success=False,
                data=None,
                message=f"区域分析失败: {str(e)}"
            )

    def get_regional_distribution(self, query, filters: RegionalAnalysisFilters) -> Dict[str, Any]:
        """获取区域分布统计"""
        # 根据区域级别进行分组统计
        if filters.region_level == 'city':
            group_by_field = RegionalAnalysisResult.dzxx_ds
        elif filters.region_level == 'district':
            group_by_field = RegionalAnalysisResult.dzxx_xzq
        elif filters.region_level == 'street':
            group_by_field = RegionalAnalysisResult.dzxx_jd
        else:
            # 默认按区县统计
            group_by_field = RegionalAnalysisResult.dzxx_xzq

        results = query.with_entities(
            group_by_field.label('region'),
            func.count().label('count')
        ).filter(group_by_field.isnot(None), group_by_field != '').group_by(
            group_by_field
        ).order_by(desc('count')).limit(20).all()

        regions = []
        counts = []

        for result in results:
            if result.region:  # 过滤空值
                regions.append(result.region)
                counts.append(result.count)

        return {
            "regions": regions,
            "counts": counts,
            "total_regions": len(regions),
            "top_region": regions[0] if regions else None,
            "top_count": counts[0] if counts else 0
        }

    def get_geographical_data(self, query, filters: RegionalAnalysisFilters) -> List[Dict[str, Any]]:
        """获取地理坐标数据"""
        # 查询有经纬度坐标的记录
        geo_query = query.filter(
            and_(
                RegionalAnalysisResult.dzxx_lng.isnot(None),
                RegionalAnalysisResult.dzxx_lat.isnot(None),
                RegionalAnalysisResult.dzxx_lng != '',
                RegionalAnalysisResult.dzxx_lat != ''
            )
        )

        # 限制返回数量以提高性能
        if filters.limit:
            geo_query = geo_query.limit(filters.limit)
        else:
            geo_query = geo_query.limit(1000)  # 默认限制1000个点

        results = geo_query.all()

        geographical_data = []
        for result in results:
            try:
                lng = float(result.dzxx_lng) if result.dzxx_lng else None
                lat = float(result.dzxx_lat) if result.dzxx_lat else None

                if lng and lat:  # 确保坐标有效
                    geographical_data.append({
                        "id": result.petition_record_id,
                        "lng": lng,
                        "lat": lat,
                        "address": result.dzxx_tsdz or "",
                        "region": f"{result.dzxx_ds or ''} {result.dzxx_xzq or ''}".strip(),
                        "complaint_content": result.xfnr[:200] + "..." if len(result.xfnr or "") > 200 else result.xfnr or "",
                        "created_at": result.created_at.isoformat(),
                        "confidence": getattr(result, 'get_confidence_score', lambda: 0.8)()
                    })
            except (ValueError, TypeError):
                # 坐标转换失败，跳过该记录
                continue

        return geographical_data

    def get_confidence_distribution(self, query, filters: RegionalAnalysisFilters) -> Dict[str, Any]:
        """获取置信度分布"""
        # 模拟置信度分布（实际项目中需要根据具体模型调整）
        confidence_ranges = {
            "高置信度 (0.8-1.0)": 0,
            "中置信度 (0.6-0.8)": 0,
            "低置信度 (0.4-0.6)": 0,
            "很低置信度 (0-0.4)": 0
        }

        total_count = query.count()

        # 简化的置信度分布计算
        if total_count > 0:
            # 假设大部分数据为高置信度
            confidence_ranges["高置信度 (0.8-1.0)"] = int(total_count * 0.7)
            confidence_ranges["中置信度 (0.6-0.8)"] = int(total_count * 0.2)
            confidence_ranges["低置信度 (0.4-0.6)"] = int(total_count * 0.08)
            confidence_ranges["很低置信度 (0-0.4)"] = total_count - sum(confidence_ranges.values())

        return {
            "ranges": list(confidence_ranges.keys()),
            "counts": list(confidence_ranges.values()),
            "total_count": total_count,
            "average_confidence": 0.75  # 模拟平均值
        }

    def _calculate_coordinate_coverage(self, query) -> float:
        """计算坐标覆盖率"""
        total_count = query.count()
        if total_count == 0:
            return 0.0

        coordinate_count = query.filter(
            and_(
                RegionalAnalysisResult.dzxx_lng.isnot(None),
                RegionalAnalysisResult.dzxx_lat.isnot(None),
                RegionalAnalysisResult.dzxx_lng != '',
                RegionalAnalysisResult.dzxx_lat != ''
            )
        ).count()

        return round((coordinate_count / total_count) * 100, 2)

    def get_regional_statistics(self, region: str, filters: RegionalAnalysisFilters) -> Dict[str, Any]:
        """获取特定区域的详细统计"""
        query = self.build_base_query(filters)

        # 筛选特定区域
        region_query = query.filter(
            or_(
                RegionalAnalysisResult.dzxx_ds == region,
                RegionalAnalysisResult.dzxx_xzq == region,
                RegionalAnalysisResult.dzxx_jd == region
            )
        )

        basic_stats = self.get_basic_statistics(filters)
        geographical_data = self.get_geographical_data(region_query, filters)

        return {
            "region": region,
            "basic_statistics": basic_stats,
            "geographical_points": len(geographical_data),
            "coordinate_coverage": self._calculate_coordinate_coverage(region_query)
        }

    def get_heatmap_data(self, filters: RegionalAnalysisFilters) -> List[Dict[str, Any]]:
        """获取热力图数据"""
        query = self.build_base_query(filters)

        # 获取有坐标的数据
        geo_query = query.filter(
            and_(
                RegionalAnalysisResult.dzxx_lng.isnot(None),
                RegionalAnalysisResult.dzxx_lat.isnot(None),
                RegionalAnalysisResult.dzxx_lng != '',
                RegionalAnalysisResult.dzxx_lat != ''
            )
        )

        results = geo_query.all()

        heatmap_data = []
        for result in results:
            try:
                lng = float(result.dzxx_lng)
                lat = float(result.dzxx_lat)
                weight = 1.0  # 默认权重，可以根据需要调整

                heatmap_data.append({
                    "lng": lng,
                    "lat": lat,
                    "weight": weight,
                    "count": 1
                })
            except (ValueError, TypeError):
                continue

        return heatmap_data

    def get_task_list(self) -> List[Dict[str, Any]]:
        """获取可用的分析任务列表"""
        tasks = self.db.query(AnalysisTask).filter(
            AnalysisTask.is_deleted == False
        ).order_by(desc(AnalysisTask.created_at)).all()

        return [
            {
                "id": task.id,
                "name": task.name or task.task_type,
                "task_type": task.task_type,
                "status": task.status.value,
                "created_at": task.created_at.isoformat()
            }
            for task in tasks
        ]